/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.spi.jsonser.abstractcefchange;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.inspur.edp.cef.api.manager.serialize.CefSerializeContext;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.entity.entity.ICefData;

import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.spi.jsonser.entity.CommonExtendSerItem;
import com.inspur.edp.cef.spi.extend.IDataExtendSerializerItem;
import com.inspur.edp.cef.spi.extend.entity.ICefEntityExtend;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public abstract class AbstractCefDataSerializer<T extends com.inspur.edp.cef.spi.jsonser.abstractcefchange.AbstractCefDataSerItem> extends JsonSerializer<ICefData> {
    protected volatile java.util.List<T> serializers;

    protected AbstractCefDataSerializer(java.util.List<T> serializers) {
        this.serializers = serializers;
    }

    private java.util.List<AbstractCefDataSerItem> serItems;

    protected java.util.List<AbstractCefDataSerItem> getSerializerItems() {
        if (serItems != null) {
            return serItems;
        }
        synchronized (this) {
            if (this.serItems == null) {
                List<AbstractCefDataSerItem> serItems = new ArrayList<>(this.serializers);
                if (this.extendList != null) {
                    this.extendList.stream().map(item -> item.getSerializerItem())
                            .filter(item -> (item != null)).forEach(serItems::add);
                } else {
                    serItems.add(new CommonExtendSerItem());
                }
                this.serItems = serItems;
            }
        }
        return serItems;
    }

    @Override
    public void serialize(ICefData value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException
    {
        jsonGenerator.writeStartObject();
        writeDataInfo(jsonGenerator, value, serializerProvider);
        writeMultiLanguageInfo(jsonGenerator, value, serializerProvider);
        jsonGenerator.writeEndObject();
    }

    public static java.util.ArrayList<AbstractCefDataSerItem> getSerializers(java.util.ArrayList<java.lang.Class> types)
            throws NoSuchMethodException, InstantiationException, InvocationTargetException, IllegalArgumentException, IllegalAccessException {
        DataValidator.checkForNullReference(types, "types");
        ArrayList<AbstractCefDataSerItem> list = new ArrayList<AbstractCefDataSerItem>();
        for (Class type : types) {
            list.add((AbstractCefDataSerItem) type.getConstructor().newInstance());
        }
        return list;
    }

    public final void writeJson(JsonGenerator jsonGenerator, Object value, SerializerProvider serializerProvider) throws IOException {
        serialize((ICefData)value, jsonGenerator, serializerProvider);
    }

    protected void writeDataInfo(JsonGenerator jsonGenerator, ICefData data, SerializerProvider serializerProvider) throws IOException {
        for (AbstractCefDataSerItem item : getSerializerItems()) {
            if (item instanceof IDataExtendSerializerItem
                && !org.springframework.util.StringUtils.isEmpty(configId)) {
                ((IDataExtendSerializerItem) item).setConfigId(configId);
            }
            item.writeEntityBasicInfo(jsonGenerator, data, serializerProvider);
        }
    }

    private void writeMultiLanguageInfo(JsonGenerator jsonGenerator, ICefData data,
        SerializerProvider serializerProvider) throws IOException {
        if (data instanceof IMultiLanguageData) {
            MultiLangSerializationUtil.serialize(jsonGenerator, (IMultiLanguageData) data);
        }
    }


    ///#region Write

    /**
     * 将枚举类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeEnum(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeString(String.valueOf(value));
    }

    /**
     * 将字符类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeString(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeString(String.valueOf(value));
    }

    /**
     * 将整数类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeInt(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeNumber(Integer.parseInt(value.toString()));
    }

    /**
     * 将小数类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeDecimal(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeNumber((BigDecimal) value);
    }

    /**
     * 将布尔类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeBool(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeBoolean(Boolean.valueOf(value.toString()));
    }

    /**
     * 将日期类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeDateTime(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        //Java版临时
        jsonGenerator.writeFieldName(propertyName);
        jsonGenerator.writeString(((Date)value).toString());
    }

    /**
     * 将二进制数组类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeBytes(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        throw new UnsupportedOperationException();
        //Java版临时屏蔽
//		String transValue = Convert.ToBase64String((byte[])((value instanceof byte[]) ? value : null));
//		writeBaseType(writer, transValue, propertyName, serializer);
    }

    /**
     * 将关联类型数据写入到Json中
     *
     * @param jsonGenerator      Json写入器
     * @param value              要写入的值
     * @param propertyName       要写入的属性名称
     * @param serializerProvider Json序列化类
     */
    protected final void writeAssociation(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        writeBaseType(jsonGenerator, value, propertyName, serializerProvider);
    }

    private void writeBaseType(JsonGenerator jsonGenerator, Object value, String propertyName, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeFieldName(propertyName);
        serializerProvider.defaultSerializeValue(value, jsonGenerator);
    }

    // endregion

    private String configId;
    @Deprecated
    public void setConfigId(String value){
        configId = value;
    }

    private List<ICefEntityExtend> extendList;

    public void addExtend(ICefEntityExtend extList){
        Objects.requireNonNull(extList);

        if(extendList == null){
            extendList = new ArrayList<>();
        }
        extendList.add(extList);
    }

    protected List<ICefEntityExtend> getExtendList(){
        return extendList == null ? Collections.emptyList() : extendList;
    }

    public void setCefSerializeContext(CefSerializeContext context) {
        if (this.getSerializerItems() != null && this.getSerializerItems().size() > 0) {
            for (AbstractCefDataSerItem item : getSerializerItems()) {
                item.setCefSerializeContext(context);
            }
        }
    }
}
